#include "AI2048.h"


AI2048::AI2048(const Board& b)
{
	m_Board = b;
}


AI2048::~AI2048()
{

}


float AI2048::EvaluateMax(int depth, float current, float alpha, float beta)
{
	while (1) {
		Board leftBoard = m_Board;
		if (leftBoard.MoveLeft())
		{
			AI2048 ai(leftBoard);
			float new_alpha = current + ai.Evaluate(depth - 1, alpha, beta, 0 /*FALSE*/);
			if (new_alpha > alpha)
				alpha = new_alpha;
			if ( !(beta > alpha) )
				break;
		}

		Board rightBoard = m_Board;
		if (rightBoard.MoveRight())
		{
			AI2048 ai(rightBoard);
			float new_alpha = current + ai.Evaluate(depth - 1, alpha, beta, 0 /*FALSE*/);
			if (new_alpha > alpha)
				alpha = new_alpha;
			if ( !(beta > alpha) )
				break;
		}

		Board upBoard = m_Board;
		if (upBoard.MoveUp())
		{
			AI2048 ai(upBoard);
			float new_alpha = current + ai.Evaluate(depth - 1, alpha, beta, 0 /*FALSE*/);
			if (new_alpha > alpha)
				alpha = new_alpha;
			if ( !(beta > alpha) )
				break;
		}

		Board downBoard = m_Board;
		if (downBoard.MoveDown())
		{
			AI2048 ai(downBoard);
			float new_alpha = current + ai.Evaluate(depth - 1, alpha, beta, 0 /*FALSE*/);
			if (new_alpha > alpha)
				alpha = new_alpha;
			if ( !(beta > alpha) )
				break;
		}

		break;
	}

	return alpha;
}


float AI2048::EvaluateMin(int depth, float current, float alpha, float beta)
{
	const Cell* cells = m_Board.AvailableCells();
	int count = m_Board.AvailableCellsCount();

	for (int i=0; i<count; i++)
	{
		Board b2 = m_Board;
		b2.Value(cells[i]) = 2;

		AI2048 ai2(b2);
		float new_beta = current + ai2.Evaluate(depth - 1, alpha, beta, 1 /*TRUE*/);
		if (new_beta < beta)
			beta = new_beta;
		if ( !(beta > alpha) )
				break;

		Board b4 = m_Board;
		b4.Value(cells[i]) = 4;

		AI2048 ai4(b4);
		new_beta = current + ai4.Evaluate(depth - 1, alpha, beta, 1 /*TRUE*/);
		if (new_beta < beta)
			beta = new_beta;
		if ( !(beta > alpha) )
				break;
	}

	return beta;
}


float AI2048::Evaluate(int depth, float alpha, float beta, int isMax)
{
	float current = m_Board.Evaluate();

	if (0 == depth || !m_Board.CanMove())
		return current;

	if (isMax)
		return EvaluateMax(depth, current, alpha, beta);
	else
		return EvaluateMin(depth, current, alpha, beta);
}


int AI2048::GetBestMove(int depth)
{
	Board l=m_Board, r=m_Board, u=m_Board, d=m_Board;
	float ll=0, rr=0, uu=0, dd=0;

	if (l.MoveLeft())
	{
		AI2048 ai(l);
		ll = ai.Evaluate(depth, -10000, 10000, 0 /*FALSE*/);
	}
	if (r.MoveRight())
	{
		AI2048 ai(r);
		rr = ai.Evaluate(depth, -10000, 10000, 0 /*FALSE*/);
	}
	if (u.MoveUp())
	{
		AI2048 ai(u);
		uu = ai.Evaluate(depth, -10000, 10000, 0 /*FALSE*/);
	}
	if (d.MoveDown())
	{
		AI2048 ai(d);
		dd = ai.Evaluate(depth, -10000, 10000, 0 /*FALSE*/);
	}

	if (ll >= rr && ll >= uu && ll >= dd)
		return 0;
	else if (rr >= ll && rr >= uu && rr >= dd)
		return 1;
	else if (uu >= rr && uu >= ll && uu >= dd)
		return 2;
	else
		return 3;
}

